/* Copyright (C) 1999-2004 by Peter Eastman

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY 
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
   PARTICULAR PURPOSE.  See the GNU General Public License for more details. */

package artofillusion;

import artofillusion.math.*;
import artofillusion.object.*;
import artofillusion.view.*;
import buoy.event.*;
import buoy.widget.*;
import java.awt.*;

/** The ObjectPreviewCanvas class displays a single object which the user can move and rotate, but
    not edit. */

public class ObjectPreviewCanvas extends ViewerCanvas
{
  private ObjectInfo objInfo;
  private boolean sizeSet;

  static final RGBColor surfaceRGB = new RGBColor(0.8f, 0.8f, 1.0f);
  static final Color surfaceColor = new Color(0.8f, 0.8f, 1.0f);

  /** Create an ObjectPreviewCanvas for previewing a particular object. */

  public ObjectPreviewCanvas(ObjectInfo obj)
  {
    this(obj, new RowContainer());
  }

  /** Create an ObjectPreviewCanvas for previewing a particular object.  The controls for setting scale,
      projection, and view direction will be add to the Panel. */

  public ObjectPreviewCanvas(ObjectInfo obj, RowContainer p)
  {
    if (obj != null)
    {
      objInfo = obj.duplicate();
      objInfo.coords.setOrigin(new Vec3());
      objInfo.coords.setOrientation(Vec3.vz(), Vec3.vy());
      objInfo.clearDistortion();
    }
    buildChoices(p);
    setTool(new RotateViewTool(null));
    setMetaTool(new MoveViewTool(null));
    setRenderMode(RENDER_SMOOTH);
    hideBackfaces = false;
  }
  
  /** This should be called whenever the object has changed. */
  
  public void objectChanged()
  {
    getObject().clearCachedMeshes();
  }
  
  /** Get the object being previewed. */

  public ObjectInfo getObject()
  {
    return objInfo;
  }

  /** Set the object being previewed. */

  public void setObject(Object3D obj)
  {
    if (objInfo == null)
      objInfo = new ObjectInfo(obj, new CoordinateSystem(), "");
    else
      objInfo.object = obj;
    objInfo.clearCachedMeshes();
  }

  public synchronized void updateImage()
  {
    Rectangle dim = getBounds();

    adjustCamera(perspectiveChoice.getSelectedIndex() == 0);
    super.updateImage();
    if (theImage == null || objInfo == null)
      return;

    // Draw the object.

    theCamera.setObjectTransform(objInfo.coords.fromLocal());
    drawObject(gr);

    // Finish up.

    drawBorder();
    if (showAxes)
      drawCoordinateAxes();
  }

  /** Draw the object. */

  protected void drawObject(Graphics g)
  {
    RenderingMesh mesh;
    
    if (objInfo == null)
      return;
    if (!sizeSet)
    {
      // When the canvas first comes up, calculate an initial scale that allows the entire object to be seen.
      
      Rectangle dim = getBounds();
      Vec3 objSize = objInfo.object.getBounds().getSize();
      double scale = 0.8*Math.min(dim.width, dim.height)/Math.max(Math.max(objSize.x, objSize.y), objSize.z);
      setScale(scale);
      theCamera.setScreenParams(0, scale, dim.width, dim.height);
      sizeSet = true;
    }
    if (renderMode == RENDER_WIREFRAME)
    {
      g.setColor(surfaceColor);
      Object3D.draw(g, theCamera, objInfo.getWireframePreview(), objInfo.getBounds());
    }
    else if (renderMode == RENDER_TRANSPARENT)
    {
      mesh = objInfo.getPreviewMesh();
      if (mesh != null)
        renderMeshTransparent(mesh, new ConstantVertexShader(surfaceRGB), theCamera, theCamera.getViewToWorld().timesDirection(Vec3.vz()), null);
    }
    else
    {
      mesh = objInfo.getPreviewMesh();
      Vec3 viewDir = theCamera.getViewToWorld().timesDirection(Vec3.vz());
      VertexShader shader;
      if (renderMode == RENDER_FLAT)
        shader = new FlatVertexShader(mesh, surfaceRGB, viewDir);
      else if (renderMode == RENDER_SMOOTH)
        shader = new SmoothVertexShader(mesh, surfaceRGB, viewDir);
      else
        shader = new TexturedVertexShader(mesh, objInfo.object, 0.0, viewDir).optimize();
      renderMesh(mesh, shader, theCamera, objInfo.object.isClosed(), null);
    }
  }

  /** When the user presses the mouse, forward events to the current tool. */

  protected void mousePressed(WidgetMouseEvent e)
  {
    requestFocus();
    activeTool = currentTool;
    if (metaTool != null && e.isMetaDown())
      activeTool = metaTool;
    activeTool.mousePressed(e, this);
  }

  protected void mouseDragged(WidgetMouseEvent e)
  {
    activeTool.mouseDragged(e, this);
  }

  protected void mouseReleased(WidgetMouseEvent e)
  {
    activeTool.mouseReleased(e, this);
  }
}